/*************************************************************
 * Unit:    raster            release 0.32                   *
 * Purpose: Morphology tools for dilatation and erosion.     *
 * Modul:   mor_tool.cc                                      *
 * Licency: GPL or LGPL                                      *
 * Copyright: (c) 1998-2024 Jaroslav Fojtik                  *
 *************************************************************/
#include <stdio.h>
#include <stdlib.h>

#include <string.h>

#include "raster.h"
#include "ras_prot.h"

#include "img_tool.h"
#include "mor_tool.h"


void Dilatation(Raster2DAbstract *Obr, uint16_t typ /*AlineProc:PAbstractLineProc*/)
{
uint16_t LengthOfRow;
int i, q1, q2, q3;
unsigned char zbytek;

  if(Obr==NULL) return;
  if(Obr->Size1D<=0 || Obr->Size2D<=0) return;

  //if AlineProc<>nil
  //	AlineProc^.InitPassing(Obr->Size2D,'Dilatating');

  if(Obr->GetPlanes()==1)		// 2-bilevel
  {
    Raster2D_1Bit NewData;
    const void *BufData;
    LengthOfRow = (Obr->Size1D+7) / 8;

    NewData.Allocate2D(Obr->Size1D, 4);
    if(NewData.Data2D==NULL) return;
    void * const Data = NewData.GetRow(3);

    zbytek =1 << (7-((Obr->Size1D+7) % 8));	// 0,8->0; 1,9->7; 2->6
    BufData = Obr->GetRow(0);		// zpracovani 0. radku}
    for(i=-1; i<=(int)Obr->Size2D; i++)	// main loop
    {
      if(i>0 && i<Obr->Size2D) BufData=Obr->GetRow(i);	// processing next row
      q3 = (i+4) % 3;			//row No.1
      q2 = (i+5) % 3;			//row No.2
      q1 = (i+6) % 3;			//row No.3

      memset(NewData.Data2D[q1],0,LengthOfRow);
      if((typ & 8) ==  8) OrR(NewData.Data2D[q1], BufData, LengthOfRow);
      if((typ & 1) ==  1) OrR(NewData.Data2D[q2], BufData, LengthOfRow);
      if((typ & 128)==128) OrR(NewData.Data2D[q3], BufData, LengthOfRow);

      memcpy(Data, BufData, LengthOfRow);
      ShlR(Data,LengthOfRow,zbytek);
      if((typ & 16)== 16) OrR(NewData.Data2D[q1], Data, LengthOfRow);
      if((typ & 32)== 32) OrR(NewData.Data2D[q2], Data, LengthOfRow);
      if((typ & 64)== 64) OrR(NewData.Data2D[q3], Data, LengthOfRow);

      memcpy(Data, BufData, LengthOfRow);
      ShrR(Data,LengthOfRow);
      if((typ & 4)==  4) OrR(NewData.Data2D[q1], Data, LengthOfRow);
      if((typ & 2)==  2) OrR(NewData.Data2D[q2], Data, LengthOfRow);
      if((typ & 256)==256) OrR(NewData.Data2D[q3], Data, LengthOfRow);

      if(i>0)
      {
        Obr->Set(i-1, *NewData.GetRowRaster(q3));
	// if AlineProc<>nil AlineProc^.NextLine;	 {Dialog s uzivatelem}
      }
    }
  }
  else				// Grayscale
  {
    Raster1D_8Bit BufData;
    Raster2D_8Bit NewData;

    LengthOfRow=2*Obr->Size1D;
    BufData.Allocate1D(Obr->Size1D);
    if(BufData.Data1D==NULL) return;
    NewData.Allocate2D(Obr->Size1D, 4);
    if(NewData.Data2D==NULL) return;
    void * const Data = NewData.GetRow(3);	// use 4th row for Data

    Obr->Get(0,BufData);		//processing row 0
    for(i=-1; i<=(int)Obr->Size2D; i++)	// main loop
    {
      if(i>0 && i<Obr->Size2D)
          Obr->Get(i,BufData);	// Processing of the next row

      q3 = (i+4) % 3;		//row No.1
      q2 = (i+5) % 3;		//row No.2
      q1 = (i+6) % 3;		//row No.3

      memset(NewData.Data2D[q1],0,LengthOfRow);
      if((typ & 8) ==  8) MaxU16((unsigned char*)NewData.Data2D[q1], (unsigned char*)BufData.Data1D, BufData.Size1D);
      if((typ & 1) ==  1) MaxU16((unsigned char*)NewData.Data2D[q2], (unsigned char*)BufData.Data1D, BufData.Size1D);
      if((typ&128) ==128) MaxU16((unsigned char*)NewData.Data2D[q3], (unsigned char*)BufData.Data1D, BufData.Size1D);

      memcpy((uint16_t*)Data+1, BufData.Data1D, LengthOfRow-2);	// Shift right 1px
      *(uint16_t*)Data = BufData.GetValue1D(0);
      if((typ & 16) ==  16) MaxU16((unsigned char*)NewData.Data2D[q1], (unsigned char*)Data, BufData.Size1D);
      if((typ & 32) ==  32) MaxU16((unsigned char*)NewData.Data2D[q2], (unsigned char*)Data, BufData.Size1D);
      if((typ & 64) ==  64) MaxU16((unsigned char*)NewData.Data2D[q3], (unsigned char*)Data, BufData.Size1D);

      memcpy((uint16_t*)Data, (uint16_t*)BufData.Data1D+1, LengthOfRow-2);	// Shift left 1px
      ((uint16_t*)Data)[Obr->Size1D-1] = BufData.GetValue1D(BufData.Size1D-1);

      if((typ & 4) ==  4) MaxU16((unsigned char*)NewData.Data2D[q1], (unsigned char*)Data, BufData.Size1D);
      if((typ & 2) ==  2) MaxU16((unsigned char*)NewData.Data2D[q2], (unsigned char*)Data, BufData.Size1D);
      if((typ &256)==256) MaxU16((unsigned char*)NewData.Data2D[q3], (unsigned char*)Data, BufData.Size1D);

      if(i>0)
      {
        Obr->Set(i-1, *NewData.GetRowRaster(q3));
        //if AlineProc<>nil AlineProc^.NextLine;	 //Dialog with user
      }
    }
  }
		// Everything passed OK
}


void Erosion(Raster2DAbstract *Obr, uint16_t typ /*AlineProc:PAbstractLineProc*/)
{
uint16_t LengthOfRow;
int i, q1, q2, q3;
unsigned char zbytek;

  if(Obr==NULL) return;
  if(Obr->Size1D<=0 || Obr->Size2D<=0) return;

  //if AlineProc<>nil
  //	AlineProc^.InitPassing(Obr->Size2D,'Dilatating');

  if(Obr->GetPlanes()==1)		// 2-bilevel
  {
    Raster2D_1Bit NewData;
    const void *BufData;
    LengthOfRow = (Obr->Size1D+7) / 8;

    NewData.Allocate2D(Obr->Size1D, 4);
    void * const Data = NewData.GetRow(3);

    zbytek =1 << (7-((Obr->Size1D+7) % 8));	// 0,8->0; 1,9->7; 2->6
    BufData = Obr->GetRow(0);		// zpracovani 0. radku}
    for(i=-1; i<=(int)Obr->Size2D; i++)	// main loop
    {
      if(i>0 && i<Obr->Size2D) BufData=Obr->GetRow(i);	// processing next row
      q3 = (i+4) % 3;			//row No.1
      q2 = (i+5) % 3;			//row No.2
      q1 = (i+6) % 3;			//row No.3

      memset(NewData.Data2D[q1],0xFF,LengthOfRow);
      if((typ & 8) ==  8) AndR(NewData.Data2D[q1], BufData, LengthOfRow);
      if((typ & 1) ==  1) AndR(NewData.Data2D[q2], BufData, LengthOfRow);
      if((typ & 128)==128) AndR(NewData.Data2D[q3], BufData, LengthOfRow);

      memcpy(Data, BufData, LengthOfRow);
      ShlR(Data,LengthOfRow,zbytek);
      if((typ & 16)== 16) AndR(NewData.Data2D[q1], Data, LengthOfRow);
      if((typ & 32)== 32) AndR(NewData.Data2D[q2], Data, LengthOfRow);
      if((typ & 64)== 64) AndR(NewData.Data2D[q3], Data, LengthOfRow);

      memcpy(Data, BufData, LengthOfRow);
      ShrR(Data,LengthOfRow);
      if((typ & 4)==  4) AndR(NewData.Data2D[q1], Data, LengthOfRow);
      if((typ & 2)==  2) AndR(NewData.Data2D[q2], Data, LengthOfRow);
      if((typ & 256)==256) AndR(NewData.Data2D[q3], Data, LengthOfRow);

      if(i>0)
      {
        Obr->Set(i-1, *NewData.GetRowRaster(q3));
	// if AlineProc<>nil AlineProc^.NextLine;	 {Dialog s uzivatelem}
      }
    }
  }
  else				// Grayscale
  {
    Raster1D_8Bit BufData;
    Raster2D_8Bit NewData;

    LengthOfRow=2*Obr->Size1D;
    BufData.Allocate1D(Obr->Size1D);
    NewData.Allocate2D(Obr->Size1D, 4);
    void * const Data = NewData.GetRow(3);	// use 4th row for Data

    Obr->Get(0,BufData);		//processing row 0
    for(i=-1; i<=(int)Obr->Size2D; i++)	// main loop
    {
      if(i>0 && i<Obr->Size2D)
          Obr->Get(i,BufData);	// Processing of the next row

      q3 = (i+4) % 3;		//row No.1
      q2 = (i+5) % 3;		//row No.2
      q1 = (i+6) % 3;		//row No.3

      memset(NewData.Data2D[q1],0xFF,LengthOfRow);
      if((typ & 8) ==  8) MinU16((unsigned char*)NewData.Data2D[q1], (unsigned char*)BufData.Data1D, BufData.Size1D);
      if((typ & 1) ==  1) MinU16((unsigned char*)NewData.Data2D[q2], (unsigned char*)BufData.Data1D, BufData.Size1D);
      if((typ&128) ==128) MinU16((unsigned char*)NewData.Data2D[q3], (unsigned char*)BufData.Data1D, BufData.Size1D);

      memcpy((uint16_t*)Data+1, BufData.Data1D, LengthOfRow-2);	// Shift right 1px
      *(uint16_t*)Data = BufData.GetValue1D(0);
      if((typ & 16) ==  16) MinU16((unsigned char*)NewData.Data2D[q1], (unsigned char*)Data, BufData.Size1D);
      if((typ & 32) ==  32) MinU16((unsigned char*)NewData.Data2D[q2], (unsigned char*)Data, BufData.Size1D);
      if((typ & 64) ==  64) MinU16((unsigned char*)NewData.Data2D[q3], (unsigned char*)Data, BufData.Size1D);

      memcpy((uint16_t*)Data, (uint16_t*)BufData.Data1D+1, LengthOfRow-2);	// Shift left 1px
      ((uint16_t*)Data)[Obr->Size1D-1] = BufData.GetValue1D(BufData.Size1D-1);

      if((typ & 4) ==  4) MinU16((unsigned char*)NewData.Data2D[q1], (unsigned char*)Data, BufData.Size1D);
      if((typ & 2) ==  2) MinU16((unsigned char*)NewData.Data2D[q2], (unsigned char*)Data, BufData.Size1D);
      if((typ &256)==256) MinU16((unsigned char*)NewData.Data2D[q3], (unsigned char*)Data, BufData.Size1D);

      if(i>0)
      {
        Obr->Set(i-1, *NewData.GetRowRaster(q3));
        //if AlineProc<>nil AlineProc^.NextLine;	 //Dialog with user
      }
    }
  }

		// Everything passed OK
}

